/* 
 * Copyright (c) 2012, Fromentin Xavier, Schnell Michaël, Dervin Cyrielle, Brabant Quentin
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *      * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *      * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *      * The names of its contributors may not be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Fromentin Xavier, Schnell Michaël, Dervin Cyrielle OR Brabant Quentin 
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package kameleon.util;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import kameleon.exception.FileReadingException;
import kameleon.exception.FileWritingException;

/**
 * Utility class for copying files.
 * 
 * @author		Schnell Michaël
 * @version		1.0	
 */
public class IOFile {
	
	/**
	 * Buffer size for reading.
	 */
	private static final int BUFFER_SIZE = 1024 ;
	
	/**
	 * Copies the content from the given source file to the given target file.
	 * If the target file already exists, it is overridden.
	 * 
	 * @param 	source
	 * 			source file
	 * 			
	 * @param 	target
	 * 			target file
	 * 
	 * @throws 	FileReadingException
	 * 			if an error occurred while reading
	 *  
	 * @throws 	FileWritingException
	 * 			if an error occurred while writing
	 */
	public static void copyFile(File source, File target)  
			throws FileReadingException, FileWritingException {
		// Creating streams for the files
		BufferedInputStream input ;
		BufferedOutputStream output ;
		try {
			input = new BufferedInputStream(new FileInputStream(source)) ;
		} catch (FileNotFoundException e) {
			throw new FileReadingException(source) ;
		}// try
		try {
			output = new BufferedOutputStream(new FileOutputStream(target)) ;
		} catch (FileNotFoundException e) {
			throw new FileWritingException(target) ;
		}// try
		
		// Do the actual copying
		copyFile(input, output) ;
		
		// Closing the streams
		try {
			output.close() ;
		} catch (IOException e) {
			throw new FileWritingException(source) ;
		}// try
		try {
			input.close() ;
		} catch (IOException e) {
			throw new FileReadingException(source) ;
		}// try
	}// copyFile(File, File)
	
	/**
	 * Reads all the bytes read from the given {@code InputStream} and
	 * writes them to the given {@code OuuputStream}.
	 * <b>This method does not close any the given streams !</b>
	 *  
	 * @param 	source
	 * 			source of the read bytes
	 * 
	 * @param 	destination
	 * 			destination for the written bytes
	 * 
	 * @throws	FileReadingException
	 * 			if an error occurred while reading
	 *  
	 * @throws 	FileWritingException
	 * 			if an error occurred while writing
	 * 			
	 */
	public static void copyFile(InputStream source, OutputStream destination) 
			throws FileReadingException, FileWritingException {
		final byte[] buffer = new byte[BUFFER_SIZE] ;
		int nBytes ;
		while ((nBytes = read(source, buffer)) != -1) {
			write(destination, buffer, nBytes) ;
		}// while
	}// copyFile(InputStream, String)
	
	/**
	 * Reads bytes from the given {@code InputStream} and puts them into the given byte array.
	 * The number of bytes read can be at most {@code buffer.length}.
	 * 
	 * @param 	source
	 * 			{@code InputStream} from where the byte are read
	 * 
	 * @param 	buffer
	 * 			target array for the bytes
	 * 
	 * @return	Number of read bytes
	 * 
	 * @throws 	FileReadingException
	 * 			if an error occurred while reading the {@code InputStream}
	 */
	private static final int read(InputStream source, byte[] buffer) throws FileReadingException {
		try {
			return source.read(buffer, 0, buffer.length) ;
		} catch (IOException e) {
			throw new FileReadingException() ;
		}// try
	}// read(InputStream, byte[])
	
	/**
	 * Writes all the bytes from the given array into the given {@code OutputStream}.
	 * 
	 * @param 	destination
	 * 			target {@code OutputStream} for the written bytes
	 * 
	 * @param 	buffer
	 * 			source array for the bytes
	 * 
	 * @param	nBytes
	 * 			the number of written bytes
	 * 
	 * @throws 	FileWritingException
	 * 			if an error occurred while writing
	 */
	private static final void write(OutputStream destination, byte[] buffer, int nBytes) throws FileWritingException {
		try {
			destination.write(buffer, 0, nBytes) ;
		} catch (IOException e) {
			throw new FileWritingException() ;
		}// try
	}// write(OutputStream, byte[])

}// class IOFile